package org.example.demo;

import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.*;

/**
 * 实现一个简单流
 */
public class Demo09<T> {
    public static void main(String[] args) {
        List<Integer> integerList = Arrays.asList(1, 2, 3, 4, 5, 1, 2, 3, 4);
        System.out.println("基础流操作展示：");
        Demo09.of(integerList)
                .filter(integer -> integer > 3)
                .map(integer -> integer + "转换后")
                .forEach(System.out::println);

        System.out.println("------------------");
        System.out.println("简化流操作示例：");
        System.out.println(Demo09.of(integerList).reduce(Integer::max, 0));

        System.out.println("------------------");
        System.out.println("收集流操作示例一：HashSet收集");
        HashSet<Object> set = Demo09.of(integerList).collect(HashSet::new, HashSet::add);
        System.out.println(set);

        System.out.println("------------------");
        System.out.println("收集流操作示例二-：StringBuilder收集");
        StringBuilder stringBuilder = Demo09.of(integerList).collect(StringBuilder::new, StringBuilder::append);
        System.out.println(stringBuilder.toString());

        System.out.println("------------------");
        System.out.println("收集流操作示例三-StringJoiner收集：");
        StringJoiner joiner = Demo09.of(integerList).collect(() -> new StringJoiner("-"), (stringJoiner, t) -> stringJoiner.add(String.valueOf(t)));
        System.out.println(joiner.toString());

        System.out.println("------------------");
        System.out.println("收集流操作示例四-StringJoiner收集优化：");
        StringJoiner stringJoiner = Demo09.of(integerList).map(String::valueOf).collect(() -> new StringJoiner("--"), StringJoiner::add);
        System.out.println(stringJoiner.toString());

        System.out.println("------------------");
        System.out.println("收集流操作示例五-map收集：");
        HashMap<Integer, Integer> hashMap1 = Demo09.of(integerList).collect(HashMap::new, (map, t) -> {
            // 注意这里是 没有key的时候 设置1
            if (!map.containsKey(t)) {
                map.put(t, 1);
            } else {
                // 有值得时候 取出里面的值 然后在基础上加1
                Integer time = map.get(t);
                map.put(t, time + 1);
            }
        });
        System.out.println(hashMap1);

        System.out.println("------------------");
        System.out.println("收集流操作示例六-map收集优化：");
        /**
         * map.computeIfAbsent(k,v)
         * computeIfAbsent方法接受一个key和一个函数对象 value
         * computeIfAbsent作用：如果key存在，那么返回key的值
         *                     如果key不存在，那么按照函数对象，创建一个value，并将key和value存入map中
         * getAndIncrement是AtomicInteger的方法，调用这个方法的作用，是将我们从computeIfAbsent方法中获取到的值，增加1
         * 这里重点需要理解的是getAndIncrement是AtomicInteger的方法
         *
         * 注意：k->new AtomicInteger()，这里我们使用的lambda而不是AtomicInteger::new
         * 我们这里用的是k  不是t，如果使用的是AtomicInteger::new会默认使用AtomicInteger的有参构造，导致数据异常，需要谨慎
         */
        HashMap<Integer, AtomicInteger> hashMap2 = Demo09.of(integerList).collect(HashMap::new, (map, t) -> map.computeIfAbsent(t, k->new AtomicInteger()).getAndIncrement());
        System.out.println(hashMap2);
    }

    /**
     * 需求：
     * 1.通过of方法实现，集合转换成流
     * 2.通过filter方法，实现集合元素过滤
     * 3.通过map方法，实现集合元素转换
     * 4.通过foreach方法，实现集合元素遍历
     */

    // 创建一个私有的构造器
    private Demo09(Collection<T> collection) {
        this.collection = collection;
    }

    // 创建一个集合属性
    private Collection<T> collection;

    // 相当于一个工厂方法
    public static <T> Demo09<T> of(Collection<T> collection) {
        return new Demo09<T>(collection);
    }

    private Demo09<T> filter(Predicate<T> predicate) {
        List<T> filterCollection = new ArrayList<>();
        // 这里的操作 应该是对自己的集合进行，所以要对collection进行操作
        for (T t : collection) {
            if (predicate.test(t)) {
                filterCollection.add(t);
            }
        }
        return new Demo09<>(filterCollection);
    }

    private <R> Demo09<R> map(Function<T, R> function) {
        List<R> mapCollection = new ArrayList<>();
        for (T t : collection) {
            R result = function.apply(t);
            mapCollection.add(result);
        }
        return new Demo09<>(mapCollection);
    }

    private void forEach(Consumer<T> consumer) {
        for (T t : collection) {
            consumer.accept(t);
        }
    }

    /**
     * 进行简化操作，比如：找最大值，最小值，平均值等
     */
    private T reduce(BinaryOperator<T> binaryOperator, T init) {
        // 这种需要多个参数比较的形式，我们需要有个初始的参考值

        // 与此同时 我们需要一个在外部的 用来存储最终结果的值
        T p = init;
        for (T t : collection) {
            // 将p和 t  进行处理 得到的结果保存到p  然后继续用 p和下一个t比较  直到最后的结果获取到
            p = binaryOperator.apply(t, p);
        }
        return p;
    }

    /**
     * 简单流之数据收集
     * 这里注意泛型的位置在返回值之前
     */
    private <C> C collect(Supplier<C> supplier, BiConsumer<C, T> biConsumer) {
        // 创建一个容器
        C c = supplier.get();
        // 将向容器中添加元素的操作
        for (T t : collection) {
            biConsumer.accept(c, t);
        }
        return c;
    }
}
